// Copyright 2022 Huawei Cloud Computing Technology Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


#ifndef CLOUDAPPENGINE_CAERTSACLIENTSOCKET_H
#define CLOUDAPPENGINE_CAERTSACLIENTSOCKET_H

#include <pthread.h>
#include <string>
#include "CaeClientService.h"
#include "../cae_socket/CaeSocket.h"
#include "../cae_agent/CaeSocketAgent.h"
#include "IHRTSAEngine.h"
#include "HRTSAEngineParam.h"
#include "IMediaTransportEngine.h"
#include "EventReporter.h"

// 毫秒转换为RTP时间戳的倍率
constexpr int kMsToRtpTimestamp = 90;
// 音频固定的单帧采样数
constexpr int kAudioNumSamplesPerFrame = 480;

static const int MAX_SIGNATURE_EXPIRE_TIME_OUT = 6 * 60 * 60;
#define SHA256_DIGEST_SIZE (256 / 8)
#define SHA256_BLOCK_SIZE  (512 / 8)

#define SHFR(x, n)    (x >> n)
#define ROTR(x, n)   ((x >> n) | (x << ((sizeof(x) << 3) - n)))
#define CH(x, y, z)  ((x & y) ^ (~x & z))
#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))

#define SHA256_F1(x) (ROTR(x,  2) ^ ROTR(x, 13) ^ ROTR(x, 22))
#define SHA256_F2(x) (ROTR(x,  6) ^ ROTR(x, 11) ^ ROTR(x, 25))
#define SHA256_F3(x) (ROTR(x,  7) ^ ROTR(x, 18) ^ SHFR(x,  3))
#define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10))

#define UNPACK32(x, str)                      \
{                                             \
*((str) + 3) = (unsigned char) ((x)      );   \
*((str) + 2) = (unsigned char) ((x) >>  8);   \
*((str) + 1) = (unsigned char) ((x) >> 16);   \
*((str) + 0) = (unsigned char) ((x) >> 24);   \
}

#define PACK32(str, x)                        \
{                                             \
*(x) = ((unsigned int) *((str) + 3) )         \
| ((unsigned int) *((str) + 2) <<  8)         \
| ((unsigned int) *((str) + 1) << 16)         \
| ((unsigned int) *((str) + 0) << 24);        \
}

#define SHA256_SCR(i) { w[i] = SHA256_F4(w[i-2]) + w[i-7] + SHA256_F3(w[i-15]) + w[i-16];}

class HMACSHA256
{
public:
    HMACSHA256() {}
    virtual ~HMACSHA256() {}

public:
    std::string HMAC_SHA256(std::string msg, std::string key);

private:
    void sha256_init();
    void sha256_update(const unsigned char *message, unsigned int len);
    void sha256_final(unsigned char *digest);
    void sha256(const unsigned char *message, unsigned int len, unsigned char *digest);
    void sha256_transf(const unsigned char *message, unsigned int block_nb);
    std::string getHash(unsigned char*);

    unsigned int m_total_len;
    unsigned int m_current_len;
    unsigned char m_hash_block[2 * SHA256_BLOCK_SIZE];
    unsigned int m_raw_hash[8];
};

// Interface - 处理RTSA服务器接收事件函数的接口
class IStreamEngineEventHandler {
public:
    virtual void OnJoinRoomSuccess(const char* userId, const char* roomId, int elapsed) {}

    virtual void OnRemoteUserOnline(const char* userId) {}

    virtual void OnRemoteUserOffline(const char* userId, int reason) {}

    virtual void OnStartPublishStream(int code, const char* taskId) {}

    virtual void OnStopPublishStream(int code, const char* taskId) {}

    virtual void OnRequestKeyFrame(const char* userId, const huawei::rtsa::HRTSAStreamType streamType) {}

    virtual void OnLocalVideoBitrateUpdate(const huawei::rtsa::HRTSAStreamType streamType, unsigned int targetEncBitrate) {}

    virtual void OnLocalVideoBandwidthDistribution(unsigned long bandwidth, huawei::rtsa::HRTSABandwidthDistribution* result) {}

    virtual void OnRemoteCommandPacket(const char* userId, const unsigned char* packet, unsigned int length) {}

    virtual void OnLocalVideoStatsNotify(const huawei::rtsa::UpNetworkVideoStatics* connectionStatics,
        const huawei::rtsa::VideoSendStaticsInfo* videoSendStatics) {}

    virtual void OnLocalAudioStatsNotify(const huawei::rtsa::AudioSendStaticsInfo* audioSendStatics) {}

    virtual void OnLeaveRoom(huawei::rtsa::HRTSALeaveReason reason, const huawei::rtsa::HRTSALeaveStatsInfo* statsInfo) {}

    virtual void OnTransportReady() {};

    virtual void OnTransportClosed() {};

    virtual void OnRemoteVideoStateChangedNotify(const char* userId, const huawei::rtsa::HRTSAStreamType streamType,
        huawei::rtsa::HRTSARemoteVideoStreamState state, huawei::rtsa::HRTSARemoteVideoStreamStateReason reason) {}

    virtual void OnRemoteVideoFrameData(const char* userId, const huawei::rtsa::HRTSAStreamType streamType,
        const unsigned char* frame, unsigned int length, huawei::rtsa::HRTSAFrameVideoOption option) {}

    virtual void OnRemoteVideoStatsNotify(const huawei::rtsa::DownNetworkVideoStatics* connectionStatics,
        const huawei::rtsa::VideoRecvStaticsInfo* videoRecvStatics) {}

    virtual void OnRemoteAudioStateChangedNotify(const char *userId, huawei::rtsa::HRTSARemoteAudioStreamState state,
        huawei::rtsa::HRTSARemoteAudioStreamStateReason reason) {};
    
    virtual void OnRemoteAudioFrameData(const char *userId, const unsigned char *frame, unsigned int length,
        huawei::rtsa::HRTSAFrameAudioOption option) {};

    virtual ~IStreamEngineEventHandler() = default;
    IStreamEngineEventHandler(const IStreamEngineEventHandler&) = delete;
    IStreamEngineEventHandler& operator=(const IStreamEngineEventHandler&) = delete;
    IStreamEngineEventHandler(IStreamEngineEventHandler&&) = delete;
    IStreamEngineEventHandler& operator=(IStreamEngineEventHandler&&) = delete;
    
protected:
    IStreamEngineEventHandler() = default;
};

// 继承实现RTSA的服务器事件处理，初始化需要指定IStreamEngineEventHandler指针，用于完成回调
class CaeRTSAEventHandler : public huawei::rtsa::IHRTSAEventHandler {
public:
    CaeRTSAEventHandler(IStreamEngineEventHandler* streamEngineEventHandler);

    ~CaeRTSAEventHandler() override;

    void onError(int code, const char* msg) override;

    void onWarning(int code, const char* msg) override;

    void onJoinRoomSuccess(const char* userId, const char* roomId, int elapsed) override;

    void onRemoteUserOnline(const char* userId) override;

    void onRemoteUserOffline(const char* userId, int reason) override;

    void onRequestKeyFrame(const char *userId,
                           const huawei::rtsa::HRTSAStreamType streamType) override;

    void onRemoteCommandPacket(const char *userId, const unsigned char *packet, unsigned int length) override;

    void onLocalVideoBitrateUpdate(const huawei::rtsa::HRTSAStreamType streamType, unsigned int targetEncBitrate) override;

    void onLocalVideoStatsNotify(const huawei::rtsa::UpNetworkVideoStatics *connectionStatics,
        const huawei::rtsa::VideoSendStaticsInfo *videoSendStatics) override;

    void onLocalAudioStatsNotify(const huawei::rtsa::AudioSendStaticsInfo *audioSendStatics) override;

    void onTransportReady() override;

    void onTransportClosed() override;

private:
    IStreamEngineEventHandler* m_streamEngineEventHandler = nullptr;
};


// RTSAEngine的应用实现，同时包含发送处理的回调和接收RTSA服务器事件处理
class CaeRTSAClientSocket : public CaeSocket, public IStreamEngineEventHandler {
public:

    // 初始化先指定Rtsa基本配置
    CaeRTSAClientSocket();

    ~CaeRTSAClientSocket() override;

    // ------ CaeSocket Implements Starts ------ //
    int Send(void *pkt, size_t size) override;
    // RTSA为订阅通知机制，无主动Recv调用逻辑
    int Recv(void *pkt, size_t size) override;
    // 重置服务，结束推流并退出房间
    void CloseSocket() override;
    // ------ CaeSocket Implements Ends ------ //

    // ------ IStreamEngineEventHandler Implements Starts ------ //
    void OnJoinRoomSuccess(const char* userId, const char* roomId, int elapsed) override;

    void OnRemoteUserOnline(const char* userId) override;

    void OnRemoteUserOffline(const char* userId, int reason) override;

    void OnRemoteCommandPacket(const char* userId, const unsigned char* packet, unsigned int length) override;

    void OnRequestKeyFrame(const char* userId, const huawei::rtsa::HRTSAStreamType streamType) override;

    void OnLocalVideoBitrateUpdate(const huawei::rtsa::HRTSAStreamType streamType, unsigned int targetEncBitrate) override;

    void OnLocalVideoStatsNotify(const huawei::rtsa::UpNetworkVideoStatics* connectionStatics,
        const huawei::rtsa::VideoSendStaticsInfo* videoSendStatics) override;

    void OnLocalAudioStatsNotify(const huawei::rtsa::AudioSendStaticsInfo* audioSendStatics) override;
    // ------ IStreamEngineEventHandler Implements Ends ------ //

private:
    // Private Functions //
    int CaeCreateRTSAEngine();
    // 发送视频数据，该数据去除了原本TCP打包的包头
    int SendVideoData(uint8_t* data, size_t size);
    // 发送音频数据，去除了TCP打包的包头
    int SendAudioData(uint8_t* data, size_t size);
    // 发送指令数据
    int SendCmdData(uint8_t* data, size_t size, int cmdType);
    // 发布视频流
    int StartPubVideoMainStream();
    // 停止发布视频流
    int StopPubVideoMainStream();
    // 发布音频流
    int StartPubAudioStream();
    // 主动退出房间并停止音视频流的发送
    int LeaveRoom();
    // 启动发布流线程
    void StartPublishProcess();
    // 停止发布流线程
    void StopPublishProcess();

    std::string GetSignatureLocal(const char* appid, const char* roomid, const char* userid, long long timestamp, const char* key);
    std::string GetSignatureLocal(const char* appid, const char* roomid, const char* userid, long long timestamp, bool userRole, const char* key);
    std::string GetSignature(const char* roomid, const char* userid, long long* ctime, const char* appid, const char* key);
    std::string GetSignature(const char* roomid, const char* userid, long long* ctime, bool userRole, const char* appid, const char* key);

    
    // engine
    huawei::rtsa::IHRTSAEngine* m_rtsaEngine = nullptr;
    // callback handler
    CaeRTSAEventHandler* m_rtsaEventHandler = nullptr;
    
    // Status
    bool m_bJoinRoomSuccess = false;
    bool m_videoEnable = false;
    bool m_audioEnable = false;
   
    // Video frame records
    uint64_t m_videoFrameNum = 0;
    uint32_t m_fps = 0;
    uint32_t m_width = 0;
    uint32_t m_height = 0;
    uint32_t m_lastVFrameTimestamp = 0;

    // Audio frame records
    uint64_t m_audioFrameNum = 0;

    std::atomic<bool> m_threadRunFlag {false};
    // start publish stream thread
    std::thread m_startPublishThread;
    std::mutex m_startPublishLock;
    std::condition_variable m_startPublishCond;
    bool m_startPublishTrigger = false;

    // stop publish stream thread
    std::thread m_stopPublishThread;
    std::mutex m_stopPublishLock;
    std::condition_variable m_stopPublishCond;
    bool m_stopPublishTrigger = false;

    // save last estimate bitrate kbps
    uint32_t m_lastEstimateBitrate = 0;
    // save last set to encoder bitrate bps
    uint32_t m_lastEncodeBitrate = 0;

    //reporter
    huawei::er::IHEventReporter* m_reporter = nullptr;
};

#endif // CLOUDAPPENGINE_CAERTSACLIENTSOCKET_H